package com.system.core.file;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectResult;
import com.system.base.files.mapper.SysFilesMapper;
import com.system.base.files.model.SysFiles;
import com.system.core.conf.SystemConfig;
import com.system.core.file.dto.FileKindEditor;
import com.system.core.file.dto.FileManageResultKindEditor;
import com.system.core.results.FileUploadResult;
import com.system.core.results.ResultBase;
import com.system.core.security.NameUtil;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.crypto.digest.DigestUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class FileService {
	
	private SystemConfig systemConfig;
	private OSSClient ossClient;
	private Set<String> videoExt;
	@Resource
	private SysFilesMapper sysFilesMapper;

	public FileService(SystemConfig systemConfig,OSSClient ossClient) {
		this.systemConfig = systemConfig;
		this.ossClient = ossClient;
		videoExt =  new HashSet<String>();
		videoExt.add("mp4");
		videoExt.add("avi");
		videoExt.add("mov");
		videoExt.add("mkv");
		videoExt.add("flv");
	}

	public static ResultBase copyDir(String srcPath, String destPath) {
		ResultBase result = new ResultBase();
		File dir = new File(srcPath);
		File destFile = new File(destPath);
		if (!dir.exists()) {
			result.setMessage("文件夹[" + srcPath + "]不存在，拷贝失败。");
			return result;
		}
		if (!destFile.exists()) {
			destFile.mkdirs();
		}
		if (dir.list() != null) {
			for (String name : dir.list()) {
				File children = new File(srcPath + "/" + name);
				if (children.isFile()) {
					copyFile(children.getAbsolutePath(), destFile.getAbsolutePath() + "/" + name);
				} else {
					copyDir(children.getAbsolutePath(), destFile.getAbsolutePath() + "/" + name);
				}
			}
		}
		result.setSuccess(true);
		result.setMessage("拷贝完成");
		return result;
	}

	public static ResultBase copyFile(String srcPath, String destPath) {
		ResultBase result = new ResultBase();
		File srcFile = new File(srcPath);
		if (!srcFile.exists()) {
			result.setMessage("文件[" + srcPath + "]不存在，拷贝失败。");
			return result;
		}
		File destFolder = new File(destPath).getParentFile();
		destFolder.mkdirs();
		try {
			byte[] tmp = new byte[100];
			FileInputStream fileInputStream = new FileInputStream(srcFile);
			FileOutputStream fileOutputStream = new FileOutputStream(destPath);
			int readed = 0;
			while ((readed = fileInputStream.read(tmp)) > 0) {
				fileOutputStream.write(tmp, 0, readed);
			}
			fileOutputStream.flush();
			fileOutputStream.close();
			fileInputStream.close();
		} catch (Exception e) {
			result.setMessage(e.getMessage());
			return result;
		}
		result.setSuccess(true);
		return result;
	}

	private DateTimeFormatter formater = DateTimeFormatter.ofPattern("yyyy-MM-dd");

	String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" };

	public List<File> fileFilter(String path,FilenameFilter filter) {
		List<File> fileList = new ArrayList<>();
		fileFilter(path, fileList,filter,true);
		return fileList;
	}
	private void fileFilter(String path, List<File> fileList,FilenameFilter filter,boolean clearEmptyDir) {
		File dir = new File(path);
		if (!dir.exists()) {
			return;
		}
		String[] fileNames;
		if(filter != null) {
			fileNames = dir.list(filter);
		} else {
			fileNames = dir.list();
		}
		if (fileNames != null) {
			for (String name : fileNames) {
				File children = new File(path + "/" + name);
				if (children.isFile()) {
					fileList.add(children);
				} else {
					fileFilter(children.getAbsolutePath(),fileList,filter,clearEmptyDir);
				}
			}
		}
		if (fileNames != null && fileNames.length == 0 && clearEmptyDir) {
			dir.delete();
		}
	}

	public FileManageResultKindEditor fileManage(String rootPath) {
		FileManageResultKindEditor result = new FileManageResultKindEditor();
		File currentPathFile = new File(rootPath);
		if (!currentPathFile.isDirectory()) {
			log.error("文件夹不存在，或者指定的非文件夹路径。{}", rootPath);
			return result;
		}
		if (currentPathFile.listFiles() != null) {
			for (File file : currentPathFile.listFiles()) {
				FileKindEditor fileinfo = new FileKindEditor();
				String fileName = file.getName();
				if (file.isDirectory()) {
					fileinfo.setDir(true);
					fileinfo.setHasFile(file.listFiles() != null);
					fileinfo.setFilesize(0L);
					fileinfo.setPhoto(false);
				} else if (file.isFile()) {
					String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
					fileinfo.setDir(false);
					fileinfo.setHasFile(false);
					fileinfo.setFilesize(file.length());
					fileinfo.setPhoto(Arrays.<String>asList(fileTypes).contains(fileExt));
					fileinfo.setFiletype(fileExt);
				}
				fileinfo.setFilename(fileName);
				fileinfo.setDatetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
				result.getFileList().add(fileinfo);
			}
			result.setTotalCount(result.getFileList().size());
		}
		return result;
	}

	public String getDatePath() {
		String datePath = LocalDateTime.now().format(formater);
		return "/" + datePath + "/";
	}

	public String getFileExt(String fileName) {
		if (StringUtils.isBlank(fileName)) {
			return null;
		}
		String[] names = fileName.split("\\.");
		if (names.length < 2) {
			return null;
		}
		return names[names.length - 1];
	}
	public String getFileNameNoExt(String fileName) {
		if (StringUtils.isBlank(fileName)) {
			return null;
		}
		String[] names = fileName.split("\\.");
		if (names.length < 2) {
			return fileName;
		} else {
			return StringUtils.removeEnd(fileName, "."+getFileExt(fileName));
		}
	}
	

	public String getFileName() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 
	 * <font size="3" color="red">文件上传</font><br>
	 * 
	 * @param file           Spring上传对象
	 * @param saveServerPath 保存文件根路径
	 * @return <font size="2" color="blue">保存路径</font>
	 */
	public FileUploadResult upload(MultipartFile file, String dir,Long limitKbSize) {
		String fileName = getFileName();

		return uploadByFileName(file, dir, fileName,limitKbSize);
	}

	public FileUploadResult uploadByFileNameThumb(MultipartFile file, String dir, String fileName,Long limitKbSize) {
		FileUploadResult result = uploadByFileName(file, dir, fileName,limitKbSize);
		File srcFile = new File(systemConfig.getUploadPath()+result.getUploadSavePath());
		File destFile = new File(
				srcFile.getParent(),
				NameUtil.getFileNameNoExt(srcFile.getName())+"_thumb."+NameUtil.getFileExt(srcFile.getName())
			);
		if(!srcFile.canRead()) {
			result.setSuccess(false);
			result.setMessage("文件不可读");
			return result;
		}
		if(!srcFile.exists()) {
			result.setSuccess(false);
			result.setMessage("文件不存在");
			return result;
		}
		if(!videoExt.contains(NameUtil.getFileExt(file.getOriginalFilename()))) {
			try {
				ImgUtil.scale(srcFile, destFile, 0.1f);
			} catch (Exception e) {
				result.setSuccess(false);
				result.setMessage("图片文件格式异常，请重新上传。");
			}
		}
		String dateFolder = getDatePath();
		result.setThumbUri(systemConfig.getFilePrefix() + dateFolder + destFile.getName());
		result.setThumbUrl(systemConfig.getFileHostName()+result.getThumbUri());
		if(result.getFileId()!=null) {
			var sysFiles = new SysFiles();
			sysFiles.setFileId(result.getFileId());
			sysFiles.setThumbAbsolutePath(destFile.getAbsolutePath());
			sysFiles.setThumbHash(DigestUtil.md5Hex(new File(destFile.getAbsolutePath())));
			sysFiles.setThumbRelativePath(result.getThumbUri());
			sysFilesMapper.updateByPrimaryKeySelective(sysFiles);
			result.setFileId(sysFiles.getFileId());
		}
		return result;
	}
	/**
	 *
	 * @param file 文件
	 * @param dir 目录
	 * @param fileName 文件名
	 * @param limitSize 上传文件大小限制，单位kb
	 * @return
	 */
	public FileUploadResult uploadByFileName(MultipartFile file, String dir, String fileName,Long limitKbSize) {
		FileUploadResult result = new FileUploadResult();
		String origName = file.getOriginalFilename();
		if (getFileExt(origName) == null) {
			result.setMessage("上传文件的文件信息获取失败，上传失败！");
			return result;
		}
		try {
			BufferedInputStream inputStream = new BufferedInputStream(file.getInputStream());
			int fileLength = inputStream.available();
			if(fileLength == 0) {
				result.setMessage("无文件上传");
				return result;
			}
			log.debug("[缩略图]上传文件大小：{},合计：{}Mb",
					fileLength,
					new BigDecimal(fileLength).divide(new BigDecimal(1024)).divide(new BigDecimal(1024)).setScale(2,RoundingMode.HALF_UP));
			if(limitKbSize!=null 
					&& limitKbSize>0 
					&& inputStream.available() > limitKbSize*1024) {
				result.setMessage("文件大小超限,超过系统限制大小："+limitKbSize+"Kb，您上传的文件大小："
						+new BigDecimal(fileLength).divide(new BigDecimal(1024),2,RoundingMode.HALF_UP).floatValue()+"Kb。");
				return result;
			}
			String dateFolder = getDatePath();
			File parent = new File(dir + dateFolder);
			if (!parent.exists()) {
				parent.mkdirs();
			}
			String writePath = dir + dateFolder + fileName + "." + getFileExt(origName);
			FileOutputStream outputStream = new FileOutputStream(writePath);
			byte[] buffer = new byte[100];
			Long readed = 0L;
			int tmp;
			long startTime = System.currentTimeMillis();
			while ((tmp = inputStream.read(buffer)) > 0) {
				outputStream.write(buffer,0,tmp);
				readed += tmp;
			}
			outputStream.flush();
			outputStream.close();
			inputStream.close();
			long endTime = System.currentTimeMillis();

			var sysFiles = new SysFiles();
			String hash = DigestUtil.md5Hex(new File(writePath));
			result.setTakeTime(endTime - startTime);
			result.setFileSize(readed);
			result.setMessage("上传成功");
			result.setOriginalFilename(origName);
			result.setFileExt(getFileExt(origName));
			result.setUploadSavePath(dateFolder + fileName + "." + getFileExt(origName));
			result.setUri(systemConfig.getFilePrefix()+result.getUploadSavePath());
			result.setUrl(systemConfig.getFileHostName()+result.getUri());
			
			sysFiles.setFileName(origName);
			sysFiles.setAbsolutePath(result.getUploadSavePath());
			sysFiles.setRelativePath(result.getUri());
			sysFiles.setFileHash(hash);
			sysFilesMapper.insertSelective(sysFiles);
			
			result.setFileId(sysFiles.getFileId());
			result.setSuccess(true);
			
			return result;
		} catch (IOException e) {
			e.printStackTrace();
			result.setError(400);
			result.setMessage(e.getMessage());
			return result;
		}
	}
	
	public FileUploadResult uploadByByteContent(byte[] fileContent, String origName,
			String dir, String fileName,Long limitKbSize) {
		FileUploadResult result = new FileUploadResult();
		if (getFileExt(origName) == null) {
			result.setMessage("上传文件的文件信息获取失败，上传失败！");
			return result;
		}
		try {
			log.debug("[缩略图]上传文件大小：{},合计：{}Mb",
					fileContent.length,
					new BigDecimal(fileContent.length).divide(new BigDecimal(1024)).divide(new BigDecimal(1024)).setScale(2,RoundingMode.HALF_UP));
			if(limitKbSize!=null 
					&& limitKbSize>0 
					&& fileContent.length > limitKbSize*1024) {
				result.setMessage("文件大小超限,超过系统限制大小："+limitKbSize+"Kb，您上传的文件大小："
						+new BigDecimal(fileContent.length).divide(new BigDecimal(1024),2,RoundingMode.HALF_UP).floatValue()+"Kb。");
				return result;
			}
			String dateFolder = getDatePath();
			File parent = new File(dir + dateFolder);
			if (!parent.exists()) {
				parent.mkdirs();
			}
			long startTime = System.currentTimeMillis();
			String writePath = dir + dateFolder + fileName + "." + getFileExt(origName);
			FileOutputStream outputStream = new FileOutputStream(writePath);
			outputStream.write(fileContent);
			outputStream.flush();
			outputStream.close();
			long endTime = System.currentTimeMillis();

			var sysFiles = new SysFiles();
			String hash = DigestUtil.md5Hex(new File(writePath));
			
			result.setTakeTime(endTime - startTime);
			result.setFileSize(Long.valueOf(fileContent.length));
			result.setMessage("上传成功");
			result.setOriginalFilename(origName);
			result.setFileExt(getFileExt(origName));
			result.setUploadSavePath(dateFolder + fileName + "." + getFileExt(origName));
			result.setUri(systemConfig.getFilePrefix()+result.getUploadSavePath());
			result.setUrl(systemConfig.getFileHostName()+result.getUri());
			result.setSuccess(true);
			
			sysFiles.setFileName(origName);
			sysFiles.setAbsolutePath(result.getUploadSavePath());
			sysFiles.setRelativePath(result.getUri());
			sysFiles.setFileHash(hash);
			sysFilesMapper.insertSelective(sysFiles);
			result.setFileId(sysFiles.getFileId());
			return result;
		} catch (IOException e) {
			e.printStackTrace();
			result.setError(400);
			result.setMessage(e.getMessage());
			return result;
		}
	}
	
	public FileUploadResult fileupload(@RequestPart("file") MultipartFile file,String bucketName,Long limitKbSize) throws Exception{
		FileUploadResult result = new FileUploadResult();
		String origName = file.getOriginalFilename();
		String fileName = getFileName();
		InputStream inputStream = file.getInputStream();
		int fileLength = inputStream.available();
		
		if(limitKbSize!=null 
				&& limitKbSize>0 
				&& fileLength > limitKbSize*1024) {
			result.setMessage("文件大小超限,超过系统限制大小："+limitKbSize+"Kb，您上传的文件大小："
					+new BigDecimal(fileLength).divide(new BigDecimal(1024),2,RoundingMode.HALF_UP).floatValue()+"Kb。");
			return result;
		}
		String objectName=fileName + "." + getFileExt(origName);
		long startTime = System.currentTimeMillis();
		
		
		byte[] buffered = IOUtils.toByteArray(inputStream);
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffered);
		byteArrayInputStream.mark(0);
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		// 上传文件
		PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, byteArrayInputStream);
		byteArrayInputStream.reset();
		// 获取缩略图
		
		ByteArrayInputStream generateThumbnailInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
		putObjectResult = ossClient.putObject(bucketName, objectName+".png", generateThumbnailInputStream);
		
		long endTime = System.currentTimeMillis();
		result.setTakeTime(endTime - startTime);
		result.setMessage("上传成功");
		result.setFileSize((long)buffered.length);
		result.setOriginalFilename(origName);
		result.setRequestPath(putObjectResult.getRequestId());
		result.setFileExt(getFileExt(origName));
		result.setUploadSavePath(objectName);
		result.setUrl("http://"+bucketName+".oss-cn-chengdu.aliyuncs.com/"+objectName);
		result.setSuccess(true);
		return result;
	}
}
